package org.chen.service.impl;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.chen.client.CrawlerClient;
import org.chen.client.VideoClient;
import org.chen.domain.dto.CrawlerStatisticsDTO;
import org.chen.domain.dto.VideoStatisticsDTO;
import org.chen.domain.vo.CrawlerTaskVO;
import org.chen.domain.vo.DashboardVO;
import org.chen.domain.vo.StatisticVO;
import org.chen.domain.vo.VideoTaskVO;
import org.chen.service.DashboardService;
import org.chen.util.StatisticsUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
@Service
@RequiredArgsConstructor
public class DashboardServiceImpl implements DashboardService {

    private final CrawlerClient crawlerClient;
    private final VideoClient videoClient;

    @Value("${heygen.statistics.cache-ttl:300}")
    private long cacheTtl;

    @Cacheable(value = "dashboard", key = "'dashboard_data'")
    @Override
    public DashboardVO getDashboardData() {
        try {
            // 并行获取爬虫和视频服务的数据
            CompletableFuture<CrawlerData> crawlerFuture = getCrawlerDataAsync();
            CompletableFuture<VideoData> videoFuture = getVideoDataAsync();

            // 等待所有数据获取完成
            CompletableFuture.allOf(crawlerFuture, videoFuture).join();

            // 获取结果
            CrawlerData crawlerData = crawlerFuture.get();
            VideoData videoData = videoFuture.get();

            // 组装仪表盘数据
            return assembleDashboardData(crawlerData, videoData);
        } catch (InterruptedException | ExecutionException e) {
            log.error("获取仪表盘数据失败", e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取仪表盘数据失败", e);
        }
    }

    @Async("dataTaskExecutor")
    public CompletableFuture<CrawlerData> getCrawlerDataAsync() {
        CrawlerData data = new CrawlerData();
        LocalDateTime weekAgo = LocalDateTime.now().minusWeeks(1);

        data.setStatistics(crawlerClient.getStatistics());
        data.setTrend(crawlerClient.getTaskTrend(weekAgo, LocalDateTime.now()));
        data.setRecentTasks(crawlerClient.getRecentTasks(5));

        return CompletableFuture.completedFuture(data);
    }

    @Async("dataTaskExecutor")
    public CompletableFuture<VideoData> getVideoDataAsync() {
        VideoData data = new VideoData();
        LocalDateTime weekAgo = LocalDateTime.now().minusWeeks(1);

        data.setStatistics(videoClient.getStatistics());
        data.setTrend(videoClient.getTaskTrend(weekAgo, LocalDateTime.now()));
        data.setRecentTasks(videoClient.getRecentTasks(5));

        return CompletableFuture.completedFuture(data);
    }

    private DashboardVO assembleDashboardData(CrawlerData crawlerData, VideoData videoData) {
        DashboardVO dashboard = new DashboardVO();
        List<StatisticVO> statistics = new ArrayList<>();

        // 爬虫统计
        statistics.add(StatisticsUtil.createStatistic(
                "爬虫任务总数",
                crawlerData.getStatistics().getTotalTasks(),
                crawlerData.getTrend().get("total"),
                "success"
        ));

        statistics.add(StatisticsUtil.createStatistic(
                "待处理数据",
                crawlerData.getStatistics().getPendingArticles(),
                crawlerData.getTrend().get("pending"),
                "warning"
        ));

        // 视频统计
        statistics.add(StatisticsUtil.createStatistic(
                "视频生成数",
                videoData.getStatistics().getTotalVideos(),
                videoData.getTrend().get("total"),
                "success"
        ));

        statistics.add(StatisticsUtil.createStatistic(
                "失败任务",
                videoData.getStatistics().getFailedTasks(),
                videoData.getTrend().get("failed"),
                "danger"
        ));

        dashboard.setStatistics(statistics);
        dashboard.setCrawlerTasks(crawlerData.getRecentTasks());
        dashboard.setVideoTasks(videoData.getRecentTasks());

        return dashboard;
    }

    // 内部数据类
    @Data
    private static class CrawlerData {
        private CrawlerStatisticsDTO statistics;
        private Map<String, Integer> trend;
        private List<CrawlerTaskVO> recentTasks;
    }

    @Data
    private static class VideoData {
        private VideoStatisticsDTO statistics;
        private Map<String, Integer> trend;
        private List<VideoTaskVO> recentTasks;
    }

    @Cacheable(value = "dashboard", key = "'dashboard_data_' + #days")
    @Override
    public DashboardVO getDashboardDataByDays(int days) {
        try {
            LocalDateTime endTime = LocalDateTime.now();
            LocalDateTime startTime = endTime.minusDays(days);

            // 并行获取指定天数的数据
            CompletableFuture<CrawlerData> crawlerFuture = getCrawlerDataByDaysAsync(startTime, endTime);
            CompletableFuture<VideoData> videoFuture = getVideoDataByDaysAsync(startTime, endTime);

            // 等待所有数据获取完成
            CompletableFuture.allOf(crawlerFuture, videoFuture).join();

            // 获取结果
            CrawlerData crawlerData = crawlerFuture.get();
            VideoData videoData = videoFuture.get();

            return assembleDashboardData(crawlerData, videoData);
        } catch (InterruptedException | ExecutionException e) {
            log.error("获取{}天仪表盘数据失败", days, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取仪表盘数据失败", e);
        }
    }

    @Async("dataTaskExecutor")
    protected CompletableFuture<CrawlerData> getCrawlerDataByDaysAsync(LocalDateTime startTime, LocalDateTime endTime) {
        CrawlerData data = new CrawlerData();

        data.setStatistics(crawlerClient.getStatistics());
        data.setTrend(crawlerClient.getTaskTrend(startTime, endTime));
        data.setRecentTasks(crawlerClient.getRecentTasks(5));

        return CompletableFuture.completedFuture(data);
    }

    @Async("dataTaskExecutor")
    protected CompletableFuture<VideoData> getVideoDataByDaysAsync(LocalDateTime startTime, LocalDateTime endTime) {
        VideoData data = new VideoData();

        data.setStatistics(videoClient.getStatistics());
        data.setTrend(videoClient.getTaskTrend(startTime, endTime));
        data.setRecentTasks(videoClient.getRecentTasks(5));

        return CompletableFuture.completedFuture(data);
    }



    @CacheEvict(value = "dashboard", allEntries = true)
    @Override
    public void refreshStatisticsCache() {
        log.info("刷新仪表盘统计数据缓存");
    }

    /**
     * 定时刷新缓存
     * 默认每5分钟执行一次
     */
    @Scheduled(fixedRateString = "${heygen.statistics.cache-ttl:300}000")
    public void scheduledRefreshCache() {
        log.info("定时刷新仪表盘统计数据缓存");
        refreshStatisticsCache();
    }
}